snafu_derive/
report.rs

1use quote::quote;
2use syn::{spanned::Spanned, Item, ItemFn, ReturnType, Signature};
3
4pub fn body(
5    _attr: proc_macro::TokenStream,
6    item: proc_macro::TokenStream,
7) -> syn::Result<proc_macro2::TokenStream> {
8    let item = syn::parse::<Item>(item)?;
9
10    let f = match item {
11        Item::Fn(f) => f,
12        _ => {
13            return Err(syn::Error::new(
14                item.span(),
15                "`#[snafu::report]` may only be used on functions",
16            ))
17        }
18    };
19
20    let ItemFn {
21        attrs,
22        vis,
23        sig,
24        block,
25    } = f;
26
27    let Signature {
28        constness,
29        asyncness,
30        unsafety,
31        abi,
32        fn_token,
33        ident,
34        generics,
35        paren_token: _,
36        inputs,
37        variadic,
38        output,
39    } = sig;
40
41    let output_ty = match output {
42        ReturnType::Default => quote! { () },
43        ReturnType::Type(_, ty) => quote! { #ty },
44    };
45
46    let error_ty = quote! { <#output_ty as ::snafu::__InternalExtractErrorType>::Err };
47
48    let output = if cfg!(feature = "rust_1_61") {
49        quote! { -> ::snafu::Report<#error_ty> }
50    } else {
51        quote! { -> ::core::result::Result<(), ::snafu::Report<#error_ty>> }
52    };
53
54    let captured_original_body = if asyncness.is_some() {
55        quote! { async #block.await }
56    } else {
57        quote! { (|| #block)() }
58    };
59
60    let ascribed_original_result = quote! {
61        let __snafu_body: #output_ty = #captured_original_body;
62    };
63
64    let block = if cfg!(feature = "rust_1_61") {
65        quote! {
66            {
67                #ascribed_original_result;
68                <::snafu::Report<_> as ::core::convert::From<_>>::from(__snafu_body)
69            }
70        }
71    } else {
72        quote! {
73            {
74                #ascribed_original_result;
75                ::core::result::Result::map_err(__snafu_body, ::snafu::Report::from_error)
76            }
77        }
78    };
79
80    Ok(quote! {
81        #(#attrs)*
82        #vis
83        #constness
84        #asyncness
85        #unsafety
86        #abi
87        #fn_token
88        #ident
89        #generics
90        (#inputs #variadic)
91        #output
92        #block
93    })
94}